package com.zhuangjie.shop.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zhaungjie.base.utils.BigDecimalUtils;
import com.zhaungjie.base.utils.PropertiesCopyUtils.PropertiesCopy;
import com.zhuangjie.redis.helper.RedisEnhanceOperationHelper;
import com.zhuangjie.security.provider.UserProvider;
import com.zhuangjie.shop.constant.FlavorConstant;
import com.zhuangjie.shop.constant.ShoppingCartConstant;
import com.zhuangjie.shop.dto.CartItemDTO;
import com.zhuangjie.shop.entity.CartDishFlavor;
import com.zhuangjie.shop.entity.Dish;
import com.zhuangjie.shop.entity.DishFlavor;
import com.zhuangjie.shop.service.DishFlavorService;
import com.zhuangjie.shop.service.DishService;
import com.zhuangjie.shop.service.ShoppingCartService;
import com.zhuangjie.shop.vo.CartItemVO;
import com.zhuangjie.shop.vo.DishForCartItem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 评价表 服务实现类
 * </p>
 *
 * @author zhuangjie
 * @since 2023-09-24
 */
@Service
public class ShoppingCartServiceImpl implements ShoppingCartService {
    @Autowired
    private RedisEnhanceOperationHelper redisEnhanceOperationHelper;
    @Autowired
    private DishFlavorService dishFlavorService;

    @Autowired
    private DishService dishService;

    @Autowired
    private BigDecimalUtils bigDecimalUtils;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;



    @Override
    public CartItemVO addToCart(CartItemDTO cartItemDTO) {
        // 保存到Redis中
        // 由于在controller上加了@PublicAPIForModules({ModuleSecurityNames.USER}) ,所以肯定是有user模块的用户id的
        Long userId = UserProvider.currentUserId();
        // 当前的用户购物车的完整key
        String currentUserAndShopShoppingCartKey = ShoppingCartConstant.buildShoppingCartKey(cartItemDTO.getShopId(),userId);
        // 当前菜品规格的key
        String currentDishSpecificationKey = cartItemDTO.genDishSpecificationKey();
        // 如果数据是 <= 0,那就直接删除了
        if (cartItemDTO.getCount() <= 0) {
            // Boolean isEmpty = redisTemplate.boundHashOps(currentUserAndShopShoppingCartKey).hasKey(currentDishSpecificationKey);
            redisTemplate.boundHashOps(currentUserAndShopShoppingCartKey).delete(currentDishSpecificationKey);
            // 返回null表示已经删除该规格
            return null;
        }
        // 计算价格，不能以前端传过来的为准，需要后端计算
        CartItemVO cartItemVO = reComputeCartItem(cartItemDTO);
        // 将新的规格信息保存到redis
        redisEnhanceOperationHelper.luaImplHashPutAndExpire(currentUserAndShopShoppingCartKey,currentDishSpecificationKey,cartItemVO,ShoppingCartConstant.TTL_IN_SECONDS);
        return cartItemVO;
    }




    private CartItemVO reComputeCartItem(CartItemDTO cartItemDTO) {
        DishForCartItem dishForCartItem = dishService.getOneDishForCartItem(cartItemDTO.getId());
        LambdaQueryWrapper<DishFlavor> queryDishFlavorWrapper = Wrappers.lambdaQuery(DishFlavor.class)
                .eq(DishFlavor::getDishId, cartItemDTO.getId());

        List<DishFlavor> flavors = dishFlavorService.list(queryDishFlavorWrapper);
        Boolean isInputTooMuch = (flavors == null || flavors.isEmpty()) && (cartItemDTO.getFlavors() != null && ! cartItemDTO.getFlavors().isEmpty());
        Boolean isInputTooLittle =(flavors != null && ! flavors.isEmpty()) && (cartItemDTO.getFlavors() == null || cartItemDTO.getFlavors().isEmpty());
        if ( isInputTooMuch || isInputTooLittle) {
            // 过多/过少传入口味都不合法，抛出异常
            throw new RuntimeException("非法参数-口味！");
        }
        BigDecimal basePrice = dishForCartItem.getNowPrice();
        BigDecimal flavorsAppreciationSum = new BigDecimal(0);
        if(cartItemDTO.getFlavors() != null && ! cartItemDTO.getFlavors().isEmpty()) {
            // 重新计算口味增值
            Map<Long, String> flavorIdAndValueMap = flavors.stream().collect(Collectors.toMap(cartDishFlavor -> cartDishFlavor.getId(), cartDishFlavor -> cartDishFlavor.getValue()));
            List<CartDishFlavor> selectedFlavors = cartItemDTO.getFlavors();
            for (CartDishFlavor selectedFlavor : selectedFlavors) {
                String flavorValues = flavorIdAndValueMap.get(selectedFlavor.getId());
                BigDecimal flavorAppreciation = getFlavorAppreciation(flavorValues, selectedFlavor.getName());
                if (flavorAppreciation == null) {
                    throw new RuntimeException("传入的口味值无法找到，可能商家数据已经修改！");
                }
                selectedFlavor.setAppreciation(flavorAppreciation);
                // 将值加入总增值中
                flavorsAppreciationSum = bigDecimalUtils.additionOperation(flavorsAppreciationSum,flavorAppreciation);
            }
        }
        // 规格单价specUnitPrice
        BigDecimal specUnitPrice = bigDecimalUtils.additionOperation(basePrice, flavorsAppreciationSum);

        // 设置菜品总价格
        cartItemDTO.setPrice(bigDecimalUtils.multiplicationOperation(specUnitPrice,new BigDecimal(cartItemDTO.getCount())));

        // 将菜品的信息固定下来，以防后面菜品信息修改了
        CartItemVO cartItemVO = PropertiesCopy.type(Object.class, CartItemVO.class).produce(new Object[]{cartItemDTO, dishForCartItem});
        // 组装设置总口味增值
        cartItemVO.setAppreciation(flavorsAppreciationSum);
        // 组装设置单规格价格
        cartItemVO.setSpecPrice(specUnitPrice);

        return cartItemVO;
    }

    /**
     * 从字符串形式的口味value中获得指定口味对应的增值
     *
     * @param flavorValues 风味值
     * @param name         名字
     * @return {@link BigDecimal}
     */
    private BigDecimal getFlavorAppreciation(String flavorValues, String name) {
        if(Objects.isNull(flavorValues) || Objects.isNull(name)) return null;
        String[] flavorItems = flavorValues.split(FlavorConstant.FLAVOR_SEPARATOR);
        if (flavorItems == null || flavorItems.length == 0) return null;
        for(int i = 0; i < flavorItems.length; i++) {
            String flavorItem = flavorItems[i];
            String[] flavorNameAndAppreciation = flavorItem.split(FlavorConstant.FLAVOR_NAME_AND_APPRECIATION_SEPARATOR);
            String flavorName = flavorNameAndAppreciation[0];
            if(Objects.equals(flavorName,name)) {
                // 将对应的菜品增值返回
                BigDecimal flavorAppreciation = new BigDecimal(String.valueOf(flavorNameAndAppreciation.length >= 2?flavorNameAndAppreciation[1]:0));
                return flavorAppreciation;
            }
        }
        return null;
    }

    @Override
    public List<CartItemVO> listUserShoppingCart(Long shopId) {
        Object userModuleUserId = UserProvider.currentUserId();
        Map<String, Object> userShoppingCartMap = redisEnhanceOperationHelper.getHashObjectAndParseJsonForValue(ShoppingCartConstant.buildShoppingCartKey(shopId, userModuleUserId), CartItemVO.class);
        if (userShoppingCartMap == null) {
            return new ArrayList<>();
        }
        return userShoppingCartMap.values().stream().filter(Objects::nonNull).map(object -> (CartItemVO) object).collect(Collectors.toList());
    }

    @Override
    public void clearShoppingCart(Long shopId) {
        Object userId = UserProvider.currentUserId();
        // 根据userId与shopId构建购物车key
        String shoppingCartKey = ShoppingCartConstant.buildShoppingCartKey(shopId, userId);
        // 删除购物车
        redisTemplate.delete(shoppingCartKey);
    }

    @Override
    public List<CartItemVO> listUserShoppingCartDetails(Long shopId) {
        List<CartItemVO> cartItemVOList = listUserShoppingCart(shopId);
        if (cartItemVOList == null || cartItemVOList.isEmpty()) return new ArrayList<>();
        List<Long> dishIds = cartItemVOList.stream().map(cartItemDTO -> cartItemDTO.getId()).collect(Collectors.toList());
        LambdaQueryWrapper<Dish> selectDishInfoWrapper = Wrappers.lambdaQuery(Dish.class)
                .eq(Dish::getShopId,shopId)
                .in(Dish::getId, dishIds)
                .select(Dish::getName, Dish::getImage, Dish::getLabels, Dish::getOldPrice, Dish::getNowPrice);
        //
        List<Dish> dishes = dishService.list(selectDishInfoWrapper);
        Map<Long, Dish> idAndDishMap = dishes.stream().collect(Collectors.toMap(dish -> dish.getId(), dish -> dish));
        // cartItems与dishes组装成cartItemDetail
        return cartItemVOList.stream().map(cartItemDTO ->
                PropertiesCopy.type(Object.class, CartItemVO.class).produce(new Object[]{cartItemDTO, idAndDishMap.get(cartItemDTO.getId())})
        ).collect(Collectors.toList());
    }
}
